//
// Created by Mr.Left on 2017/7/11.
//
#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "jniTest2.h"

jstring  global_jstr;
//全局引用的字符串对象
jstring global_jstr;

int compare(const int * a, const int * b){
    return (*a) - (*b);
}
JNIEXPORT jint JNICALL
Java_larkvadcheck_com_jniapplication_JNITestHelper_getIntNum(JNIEnv *env, jobject instance, jint num) {

    // TODO
    return getChar(num);
}
JNIEXPORT jstring JNICALL
Java_larkvadcheck_com_jniapplication_JNITestHelper_stringFromJNI(JNIEnv *env, jobject instance) {

    // TOD

    return (*env)->NewStringUTF(env, "JNI1");
}

JNIEXPORT jstring JNICALL
Java_larkvadcheck_com_jniapplication_JNITestHelper_setStr(JNIEnv *env, jclass type, jstring str_) {
    const char *str = (*env)->GetStringUTFChars(env, str_, 0);
    (*env)->ReleaseStringUTFChars(env, str_, str);
    return (*env)->NewStringUTF(env, str);
}


//C实现数组从小到大的排序
JNIEXPORT void JNICALL
Java_larkvadcheck_com_jniapplication_JNITestHelper_sortArray(JNIEnv *env, jobject instance,
                                                      jintArray arr_) {
   //通过java的数组，拿到C的数组指针
    jint *arr = (*env)->GetIntArrayElements(env, arr_, NULL);
    //获取java数组的大小
    jsize len = (*env)->GetArrayLength(env,arr_);
    //排序，其中compare是函数指针，用于比较大小，与java类似
    qsort(arr,len, sizeof(jint),compare);
    //操作完后同步C的数组到JAVA数组中
    (*env)->ReleaseIntArrayElements(env, arr_, arr, 0);
}



//----------------------------全局引用 主要作用：共享(可以跨多个线程)，手动控制内存使用。----------------------------------//
JNIEXPORT void JNICALL
Java_larkvadcheck_com_jniapplication_JNITestHelper_createGlobalRef(JNIEnv *env, jobject instance) {
    global_jstr = (*env)->NewStringUTF(env, "I Love You");
    //通过NewGlobalRef创建全局引用
    (*env)->NewGlobalRef(env, global_jstr);}
JNIEXPORT jstring JNICALL
Java_larkvadcheck_com_jniapplication_JNITestHelper_getGlobalRef(JNIEnv *env, jobject instance) {
    //获取全局引用
    return global_jstr;
}
JNIEXPORT void JNICALL
Java_larkvadcheck_com_jniapplication_JNITestHelper_deteleGlobalRef(JNIEnv *env, jobject instance) {
    //通过DeleteGlobalRef删除全局引用
    (*env)->DeleteGlobalRef(env, global_jstr);
}
//--------------------------------------------------------------//

//--------------------------C/C++访问Java的属性、方法---------------------------//
JNIEXPORT void JNICALL
Java_larkvadcheck_com_jniapplication_JNITestHelper_accessField(JNIEnv *env, jobject jobj) {
    //通过对象拿到Class
    jclass clz = (*env)->GetObjectClass(env, jobj);
    //拿到对应属性的ID
    jfieldID fid = (*env)->GetFieldID(env, clz, "str", "Ljava/lang/String;");
    //通过属性ID拿到属性的值
    jstring jstr = (*env)->GetObjectField(env, jobj, fid);
    //通过Java字符串拿到C字符串，第三个参数是一个出参，用来告诉我们GetStringUTFChars内部是否复制了一份字符串
    //如果没有复制，那么出参为isCopy，这时候就不能修改字符串的值了，因为Java中常量池中的字符串是不允许修改的（但是jstr可以指向另外一个字符串）
    char* cstr = (*env)->GetStringUTFChars(env, jstr, NULL);
    //在C层修改这个属性的值
    char res[20] = "I love you : ";
    strcat(res, cstr);
    //重新生成Java的字符串，并且设置给对应的属性
    jstring jstr_new = (*env)->NewStringUTF(env, res);
    (*env)->SetObjectField(env, jobj, fid, jstr_new);
    //最后释放资源，通知垃圾回收器来回收
    //良好的习惯就是，每次GetStringUTFChars，结束的时候都有一个ReleaseStringUTFChars与之呼应
    (*env)->ReleaseStringUTFChars(env, jstr, cstr);
}
//----------------------------------------------------------------------------//

//--------------------------访问静态属性NUM，修改它的值--------------------------------------------------//
JNIEXPORT void JNICALL
Java_larkvadcheck_com_jniapplication_JNITestHelper_accessStaticField(JNIEnv *env, jobject instance) {

    // TODO
//与上面类似，只不过是某些方法需要加上Static
    jclass clz = (*env)->GetObjectClass(env, instance);
    jfieldID fid = (*env)->GetStaticFieldID(env, clz, "NUM", "I");
    jint jInt = (*env)->GetStaticIntField(env, clz, fid);
    jInt++;
    (*env)->SetStaticIntField(env, clz, fid, jInt);
}
//----------------------------------------------------------------------------//

//---------------------访问Java的非静态方法---------------------//
JNIEXPORT jint JNICALL
Java_larkvadcheck_com_jniapplication_JNITestHelper_accessMethod(JNIEnv *env, jobject instance) {

    jclass clz = (*env)->GetObjectClass(env, instance);
    //拿到方法的ID，最后一个参数是方法的签名
    jmethodID mid = (*env)->GetMethodID(env, clz, "genRandomInt", "(I)I");
    //调用该方法，最后一个是可变参数，就是调用该方法所传入的参数
    //套路是如果返回是：Call返回类型Method
    jint jInt = (*env)->CallIntMethod(env, instance, mid, 100);
    return jInt;
}
//----------------------------------------------------------------------------//

//---------------------------访问Java的静态方法--------------------------------//
JNIEXPORT jstring JNICALL
Java_larkvadcheck_com_jniapplication_JNITestHelper_accessStaticMethod(JNIEnv *env, jobject instance) {

    jclass clz = (*env)->GetObjectClass(env, instance);
    jmethodID mid = (*env)->GetStaticMethodID(env, clz, "getUUID", "()Ljava/lang/String;");
    //调用java的静态方法，拿到返回值
    jstring jstr = (*env)->CallStaticObjectMethod(env, clz, mid);
    //把拿到的Java字符串转换为C的字符串
    char* cstr= (*env)->GetStringUTFChars(env, jstr, NULL);
    return (*env)->NewStringUTF(env, cstr);
}
//----------------------------------------------------------------------------//

//----------------------------JNI返回中文乱码问题------------------------------------------------//
JNIEXPORT jstring JNICALL
Java_larkvadcheck_com_jniapplication_JNITestHelper_testChineseOut(JNIEnv *env, jobject instance) {

    //return (*env)->NewStringUTF(env, returnValue);
    //需要返回的字符串
    char* c_str = "JNI返回中文乱码问题";
    //jstring j_str = (*env)->NewStringUTF(env, c_str);

    //通过调用构造方法String string = new String(byte[], charsetName);来解决乱码问题

    //0.找到String类
    jclass clz_String =  (*env)->FindClass(env, "java/lang/String");
    jmethodID mid = (*env)->GetMethodID(env, clz_String, "<init>", "([BLjava/lang/String;)V");

    //准备new String的参数：byte数组以及字符集
    //1.创建字节数组，并且将C的字符串拷贝进去
    jbyteArray j_byteArray = (*env)->NewByteArray(env, strlen(c_str));
    (*env)->SetByteArrayRegion(env, j_byteArray, 0, strlen(c_str), c_str);
    //2.创建字符集的参数，这里用Windows的more字符集UTF-8
    jstring charsetName = (*env)->NewStringUTF(env, "UTF-8");

    //调用
    jstring j_new_str = (*env)->NewObject(env, clz_String, mid, j_byteArray, charsetName);
    return j_new_str;

}
//----------------------------------------------------------------------------//
